/**
 * @author Rudy Kaplan Depena (The University of Texas at Austin)
 */
package com.utaustin.mirankerlab.ultrawrap.compiler.utilities;

import java.util.List;
import java.util.ArrayList;
import com.utaustin.mirankerlab.ultrawrap.compiler.components.Component;
import com.utaustin.mirankerlab.ultrawrap.compiler.components.Triple;
import com.utaustin.mirankerlab.ultrawrap.compiler.components.FilterConstraint;
import com.utaustin.mirankerlab.ultrawrap.compiler.components.RelationalExpr;
import com.utaustin.mirankerlab.ultrawrap.compiler.utilities.BookKeeper;
import com.utaustin.mirankerlab.ultrawrap.compiler.expressionTree.sparql.BGP;



import com.utaustin.mirankerlab.ultrawrap.compiler.exceptions.IncompleteRelationalExpressionException;

/** Carries an assortment of helpful methods to help compilation */
public class Utilities {
	
	//static variables
	public static List<BGP> bgps = new ArrayList<BGP>();

	/**
	 * This method determines whether or not the string indicates that
	 * component is a subject or subject key or object or object key
	 * 
	 * @param iriRefOrPutativeLiteral
	 * @return
	 */
	public static boolean isKey(String iriRefOrPutativeLiteral){
		if(iriRefOrPutativeLiteral == null || iriRefOrPutativeLiteral.charAt(0) == '?'){
			return false;
		}
		else{
			//if digits exist at the end, then this is identified as a key
			char digit = iriRefOrPutativeLiteral.charAt(iriRefOrPutativeLiteral.length() - 1);
			//return (digit >= '1' && digit <= '9');
			return (digit >= '0' && digit <= '9');//added to correct issue 4
		}
	}
	
	/**
	 * Finds a triple to whom the constraint belongs
	 * @param triples
	 * @param filteredConstraint
	 * @return
	 * @throws IncompleteRelationalExpressionException
	 */
	public static boolean findTripleForConstraint(List<Triple> triples, FilterConstraint filteredConstraint)
	throws IncompleteRelationalExpressionException
	{	
		if(filteredConstraint != null && filteredConstraint instanceof RelationalExpr)
		{
			if(filteredConstraint.isComplete() == false)
			{
				throw new IncompleteRelationalExpressionException(
						"This relational expression constraint is incomplete");
			}
			
			if(triples.size() > 0){
				for(Triple triple : triples)
				{
					//Acquire Subject, Predicate, Object
					String subject = triple.getSubjectOrSubjectKey().getRawImg();
					String predicate = triple.getPredicate().getRawImg();
					String object = triple.getObjectOrObjectKey().getRawImg();
					
					//Acquire Operand1, Operand2
					String operand1 = filteredConstraint.getOperand1().getRawImg();
					String operand2 = filteredConstraint.getOperand2().getRawImg();
					
					//Compare triple components with constraint components
					if(subject.equals(operand1) || subject.equals(operand2) ||
					   predicate.equals(operand1) || predicate.equals(operand2) ||
					   object.equals(operand1) || object.equals(operand2))//if found
					{
						triple.setFilteredConstraint(filteredConstraint);//then set constraint
						return true;//and return true
					}
				}	
			}
			else
			{
				for(int i = bgps.size() - 1; i >= 0; i--)
				{
					List<Triple> bgpTriples = bgps.get(i).getTriples();
					for(Triple triple : bgpTriples)
					{
						//Acquire Subject, Predicate, Object
						String subject = triple.getSubjectOrSubjectKey().getRawImg();
						String predicate = triple.getPredicate().getRawImg();
						String object = triple.getObjectOrObjectKey().getRawImg();
						
						//Acquire Operand1, Operand2
						String operand1 = filteredConstraint.getOperand1().getRawImg();
						String operand2 = filteredConstraint.getOperand2().getRawImg();
						
						//Compare triple components with constraint components
						if(subject.equals(operand1) || subject.equals(operand2) ||
						   predicate.equals(operand1) || predicate.equals(operand2) ||
						   object.equals(operand1) || object.equals(operand2))//if found
						{
							triple.setFilteredConstraint(filteredConstraint);//then set constraint
							return true;//and return true
						}
					}
				}
				
			}
			
		}
		return false;//return false if you can't find a filtered constraint
	}
	
	/**
	 * This method returns a string that will extract a key, if one exists,
	 * from the component
	 * 
	 * 
	 * @param String iriRefOrPutativeLiteral
	 * @return String key
	 */
	public static String getKey(String iriRefOrPutativeLiteral){
		StringBuilder sb = new StringBuilder();
		boolean stop = false;
		
		//find digits and extract
		for(int i = iriRefOrPutativeLiteral.length() - 1; i >= 0 && stop == false; --i){
			char digit = iriRefOrPutativeLiteral.charAt(i);
			if(digit >= '0' && digit <= '9'){
				sb.append(digit);
			}
			else{
				stop = true;
			}
		}
		
		return sb.reverse().toString();
		
	}
	
	/**
	 * Returns a SQL Select Statement
	 * @param vars
	 * @param bookKeeper
	 * @param distinct
	 * @return SQL Select Statement
	 */
	public static String sqlSelectVariables(List<Component> vars, BookKeeper bookKeeper, boolean distinct)
	{
		String sql = "";
		try{
		sql += "SELECT " + (distinct ? " DISTINCT " : "");
		for(int i = 0; i < vars.size(); ++i){
			if(i > 0){
				sql += ", t" + bookKeeper.getFirstTripleIdEncountered(vars.get(i)) + "." 
				+ bookKeeper.getFirstKindOfOccurance(vars.get(i), true) + "T" + bookKeeper.getFirstTripleIdEncountered(vars.get(i))
				+ " AS " + vars.get(i).getSanitizedImg();
			}
			else if(i == 0){
				sql += "t" + bookKeeper.getFirstTripleIdEncountered(vars.get(i)) + "." 
				+ bookKeeper.getFirstKindOfOccurance(vars.get(i), true) + "T" + bookKeeper.getFirstTripleIdEncountered(vars.get(i))
				+ " AS " + vars.get(i).getSanitizedImg();
			}
		}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return sql + " \n FROM";
	}
	
	/**
	 * Returns "s", "p", or "o" depending on whether or not filtered constraint operands
	 * correspond to subject, predicate or object respectively
	 * @param s
	 * @param p
	 * @param o
	 * @param operand
	 * @return "s", "p", or "o"
	 */
	public static String givenConstraintGiveSPO(Component s, Component p, Component o, Component operand)
	{
		if(s.getRawImg().equals(operand.getRawImg()))
		{
			return "s";
		}
		if(p.getRawImg().equals(operand.getRawImg()))
		{
			return "p";
		}
		if(o.getRawImg().equals(operand.getRawImg()))
		{
			return "o";	
		}
		return null;
	}
	
}
